#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <cerrno>
#include <unordered_map>
#include <functional>
#include "Sock.hpp"
#include "Epoller.hpp"
#include "Log.hpp"
#include "Util.hpp"
#include "Protocol.hpp"

// 基于Reactor模式，编写一个充分读取和写入的，EPOLL(ET)的Server

class Connection;
class TcpServer;

using func_t = std::function<int(Connection *)>;
using callback_t = std::function<int(Connection *, std::string &)>;

// event
class Connection
{
public:
    // 文件描述符
    int sock_;
    TcpServer *R_;
    // 自己的接受和发送缓冲区
    std::string inbuffer_;
    std::string outbuffer_;
    // 回调函数
    func_t recver_; 
    func_t sender_;
    func_t excepter_;

    // 有效报文的集合
    // std::vector<std::string> requests;

    // status
    // int status;

public:
    Connection(int sock, TcpServer *r) : sock_(sock), R_(r)
    {
    }
    void SetRecver(func_t recver) { recver_ = recver; }
    void SetSender(func_t sender) { sender_ = sender; }
    void SetExcepter(func_t excepter) { excepter_ = excepter; }
    ~Connection() {}
};

//Reactor
//单进程：半异步半同步 -- Reactor -- Linux服务最常用 -- 几乎没有之一
// Reactor（tcp）服务器, 即负责事件派发, 又负责IO [又负责业务逻辑的处理]

// Proactor: 前摄模式 -- 其他平台可能出现的模式
// 只负责负责事件派发，就绪的事件推送给后端的进程、线程池， 不关心 负责IO [又负责业务逻辑的处理]

class TcpServer
{
public:
    TcpServer(callback_t cb, int port = 8080) : cb_(cb)
    {
        revs_ = new struct epoll_event[revs_num];
        // 网络功能
        listensock_ = Sock::Socket();
        Util::SetNonBlock(listensock_);
        Sock::Bind(listensock_, port);
        Sock::Listen(listensock_);

        // 多路转接
        epfd_ = Epoller::CreateEpoller();

        // 添加listensock匹配的connection
        AddConnection(listensock_, EPOLLIN | EPOLLET,
                      std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

        // // 添加listensock到epoll
        // Epoller::AddEvent(epfd_, listensock_, EPOLLIN | EPOLLET);

        // // 将listensock匹配的Connection也添加到当前的unordered_map中
        // Connection *conn = new Connection(listensock_, this);
        // conn->SetRecver(std::bind(&TcpServer::Accepter, this, std::placeholders::_1));

        // connections_.insert(std::make_pair(listensock_, conn));
    }
    void AddConnection(int sockfd, uint32_t event, func_t recver, func_t sender, func_t excepter)
    {
        if (event & EPOLLET)
            Util::SetNonBlock(sockfd);
        // 添加sockfd到epoll
        Epoller::AddEvent(epfd_, sockfd, event);
        // 将sockfd匹配的Connection也添加到当前的unordered_map中
        Connection *conn = new Connection(sockfd, this);
        conn->SetRecver(recver);
        conn->SetSender(sender);
        conn->SetExcepter(excepter);

        // conn->SetRecver(std::bind(&TcpServer::TcpRecver, this, std::placeholders::_1));
        // conn->SetSender(std::bind(&TcpServer::TcpSender, this, std::placeholders::_1));
        // conn->SetExcepter(std::bind(&TcpServer::TcpExcepter, this, std::placeholders::_1));

        connections_.insert(std::make_pair(sockfd, conn));
        logMessage(DEBUG, "添加新链接到connections成功: %d", sockfd);
    }
    int Accepter(Connection *conn)
    {
        // demo - listensock 也是工作在ET，来一个连接，对应就有事件就绪，那么如何来一批呢？
        while (true)
        {
            std::string clientip;
            uint16_t clientport = 0;
            int sockfd = Sock::Accept(conn->sock_, &clientip, &clientport);
            if (sockfd < 0)
            {
                if (errno == EINTR)
                    continue;
                else if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else
                {
                    logMessage(WARNING, "accept error");
                    return -1;
                }
            }
            logMessage(DEBUG, "get a new link: %d", sockfd);
            // 注意：默认我们只设置了让epoll帮我们关心读事件，没有关心写事件
            // 为什么没有关注写事件：因为最开始的时候，写空间一定是就绪的！
            // 运行中可能会存在条件不满足 -- 写空间被写满了
            AddConnection(sockfd, EPOLLIN | EPOLLET,
                          std::bind(&TcpServer::TcpRecver, this, std::placeholders::_1),
                          std::bind(&TcpServer::TcpSender, this, std::placeholders::_1),
                          std::bind(&TcpServer::TcpExcepter, this, std::placeholders::_1));
        }
        return 0;
    }

    int TcpRecver(Connection *conn)
    {
        // XXXXXXX\3XXXXXX\3
        while (true)
        {
            char buffer[1024];
            ssize_t s = recv(conn->sock_, buffer, sizeof(buffer) - 1, 0);
            if (s > 0)
            {
                buffer[s] = 0;
                conn->inbuffer_ += buffer;
            }
            else if (s == 0)
            {
                logMessage(DEBUG, "client quit");
                conn->excepter_(conn);
                break;
            }
            else
            {
                if (errno == EINTR)
                    continue;
                else if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else
                {
                    // 出错了
                    logMessage(DEBUG, "recv error: %d:%s", errno, strerror(errno));
                    conn->excepter_(conn);
                    break;
                }
            }
        }
        // 将本轮全部读取完毕
        std::vector<std::string> result;
        PackageSplit(conn->inbuffer_, &result);
        for (auto &message : result)
        {
            cb_(conn, message);
        }
        return 0;
    }
    int TcpSender(Connection *conn)
    {
        while(true)
        {
            ssize_t n = send(conn->sock_, conn->outbuffer_.c_str(), conn->outbuffer_.size(), 0);
            if(n > 0)
            {
                // 去除已经成功发送的数据
                conn->outbuffer_.erase(0, n);
            }
            else
            {
                if(errno == EINTR) continue;
                else if(errno == EAGAIN || errno == EWOULDBLOCK) break; //发完了，一定是outbuffer清空了吗？不一定(EPOLLOUT打开)
                else
                {
                    conn->excepter_(conn);
                    logMessage(DEBUG, "send error: %d:%s", errno, strerror(errno));
                    break;
                }
            }
        }
        // if(conn->outbuffer_.empty()) EnableReadWrite(conn->sock_, true, false);
        // else EnableReadWrite(conn->sock_, true, true);
        return 0;
    }
    int TcpExcepter(Connection *conn)
    {
        // 0.
        if(!IsExists(conn->sock_)) return -1;
        
        // 所有的服务器异常，都会被归类到这里
        // 坑：一定要先从epoll中移除，然后再关闭fd
        // 1.
        Epoller::DelEvent(epfd_, conn->sock_);
        logMessage(DEBUG, "remove epoll event!");
        // 2.
        close(conn->sock_);
        logMessage(DEBUG, "close fd: %d", conn->sock_);
        // 3. delete conn;
        delete connections_[conn->sock_];
        logMessage(DEBUG, "delete connection object done");
        // 4. 
        connections_.erase(conn->sock_);
        logMessage(DEBUG, "erase connection from connections");

        return 0;
    }
    bool IsExists(int sock)
    {
        auto iter = connections_.find(sock);
        if (iter == connections_.end())
            return false;
        else
            return true;
    }
    // 打开或者关闭对于特定socket是否要关心读或者写
    //EnableReadWrite(sock, true, false);
    //EnableReadWrite(sock, true, true);
    void EnableReadWrite(int sock, bool readable, bool writeable)
    {
        uint32_t event = 0;
        event |= (readable ? EPOLLIN : 0);
        event |= (writeable ? EPOLLOUT : 0);
        Epoller::ModEvent(epfd_, sock, event);
    }
    // 根据就绪事件，将事件进行事件派发
    void Dispatcher()
    {
        int n = Epoller::LoopOnce(epfd_, revs_, revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = revs_[i].data.fd;
            uint32_t revent = revs_[i].events;
            if(revent & EPOLLHUP) revent |= (EPOLLIN|EPOLLOUT);
            if(revent & EPOLLERR) revent |= (EPOLLIN|EPOLLOUT);

            if (revent & EPOLLIN)
            {
                if (IsExists(sock) && connections_[sock]->recver_)
                    connections_[sock]->recver_(connections_[sock]);
            }
            if (revent & EPOLLOUT)
            {
                if (IsExists(sock) && connections_[sock]->sender_)
                    connections_[sock]->sender_(connections_[sock]);
            }
        }
    }
    void Run()
    {
        while (true)
        {
            Dispatcher();
        }
    }
    ~TcpServer()
    {
        if (listensock_ != -1)
            close(listensock_);
        if (epfd_ != -1)
            close(epfd_);
        delete[] revs_;
    }

private:
    static const int revs_num = 64;
    // 1. 网络socket
    int listensock_;
    // 2. epoll
    int epfd_;
    // 3. 将epoll和上层代码进行结合
    std::unordered_map<int, Connection *> connections_;
    // 4. 就绪事件列表
    struct epoll_event *revs_;
    // 5. 设置完整报文的处理方法
    callback_t cb_;

    // "http", httpservice;
    // std::unordered_map<std::string, callback_t> cbs_;
};